
#include "TTGXMLTree.h"

using namespace std;
using namespace ttg_internal;
using namespace ttg::structures;
using namespace ttg::extras;

//------------------
//--- TTGXMLTree ---
//------------------

//--- private ---

#define throwError throw Error(Error::LOCAL, "FileParser", "readSectionNode", "Wrong content or corrupted file")

//first tag is contained in lexer
int TTGXMLTree::loadNextNode(SectionNode *node)
{
	int type;
	char *name;
	SectionNode *snode;
	while ((type = lexer->getType()) != Lexer::XML_ERROR)
		switch (type)
		{
			case Lexer::XML_TAG_COMMENT:          //skipping
			case Lexer::XML_TAG_INF: lexer->readNext(); break;

			case Lexer::XML_TAG_OPEN:
				name = strings::createCopy(lexer->showTag());
				if ((type = lexer->readNext()) == Lexer::XML_ERROR ||
					type == Lexer::XML_END_OF_FILE)
				{
					delete[] name;
					return XML_ERROR;
				}
				if (type == Lexer::XML_TAG_CLOSE) //it's attr
				{
					if (!strcmp(name, lexer->showTag()))
					{
						node->addAttr(new AttributeNode(name, lexer->showValue()));
						lexer->readNext();
						delete[] name;
						return ALL_OK;
					}
					else
					{
						delete[] name;
						return XML_ERROR;
					}
				}
				else //it's another section
				{
					int status;
					snode = new SectionNode(name, node);
					node->addSection(snode);
					while ((status = this->loadNextNode(snode)) == ALL_OK);
					snode->resetIterators();
					if (status == END_OF_SECTION && !strcmp(name, lexer->showTag()))
					{
						delete[] name;
						lexer->readNext();
						return ALL_OK;
					}
					delete[] name;
					return XML_ERROR;
				}

			case Lexer::XML_END_OF_FILE:
			case Lexer::XML_TAG_CLOSE: return END_OF_SECTION;



			default: return XML_ERROR;
		}
	return XML_ERROR;
}

void TTGXMLTree::saveNextNode(SectionNode *node)
{
	lexer->addTag(Lexer::XML_TAG_OPEN, node->getName());
	node->resetIterators();
	const AttributeNode *att;
	while ((att = node->getNextAttribute()) != NULL)
	{
		lexer->addTag(Lexer::XML_TAG_OPEN, att->getName());
		lexer->addValue(att->getValue());
		lexer->addTag(Lexer::XML_TAG_CLOSE, att->getName());
	}
	SectionNode *s;
	while ((s = node->getNextSection()) != NULL)
		this->saveNextNode(s);
	lexer->addTag(Lexer::XML_TAG_CLOSE, node->getName());
}

TTGXMLTree::TTGXMLTree(int access, SectionNode *root)
	:XMLTree(root->getName())
{
	this->access = access;
	this->root = root;
	this->currentnode = root;
}

TTGXMLTree::TTGXMLTree(int access, SectionNode *root, list<XMLTree *> *explorers)
	:XMLTree(root->getName(), explorers)
{
	this->access = access;
	this->root = root;
	this->currentnode = root;
}

//--- public ---

TTGXMLTree::TTGXMLTree()
	:XMLTree("root")
{
	this->root = NULL;
	this->currentnode = NULL;
	this->lexer = NULL;
	this->access = XML_RO;
}

void TTGXMLTree::assign(AccessType access, const char *filename)
{
	FILE *source;
	int status;
	this->access = access;
	this->root = new SectionNode("root", NULL);
	this->currentnode = root;
	if (access == XML_RO)
	{
		if (fopen_s(&source, filename, "r") != 0)
			throw Error(Error::LOCAL,
						"FileParser",
						"assign",
						"Cannot open file",
						filename);
		lexer = new Lexer(source);
		lexer->readNext();
		while ((status = this->loadNextNode(root)) == ALL_OK);
		if (status != END_OF_SECTION)
			throw Error(Error::LOCAL,
						"FileParser",
						"assign",
						"EOF not found",
						filename);
		root->resetIterators();
	} else
	if (access == XML_WO)
	{
		if (fopen_s(&source, filename, "w") != 0)
			throw Error(Error::LOCAL,
						"FileParser",
						"assign",
						"Cannot create file",
						filename);
		lexer = new Lexer(source);
	}
}

void TTGXMLTree::close()
{
	if (!this->isExplorer())
	{
		if (access == XML_WO && root != NULL)
		{
			SectionNode *snode;
			root->resetIterators();
			while ((snode = root->getNextSection()) != NULL)
				this->saveNextNode(snode);
		}
		if (root != NULL)
			delete root;
		if (lexer != NULL)
			delete lexer;
	}
	root = NULL;
	lexer = NULL;
	currentnode = NULL;
}

XMLTree &TTGXMLTree::getSubXMLTree()
{
	return *(new TTGXMLTree(access, currentnode, this->getExplorers()));
}

bool TTGXMLTree::openSection(const char *section)
{
	list <SectionNode *>::iterator it = currentnode->sectionnodes.begin();
	while (it != currentnode->sectionnodes.end())
		if (!strcmp((*it)->getName(), section))
		{
			currentnode = *it;
			return true;
		}
		else
			it++;
	return false;
}

bool TTGXMLTree::closeSection()
{
	if (currentnode != root)
	{
		currentnode = currentnode->parent;
		return true;
	}
	else
		return false;
}

const char *TTGXMLTree::getCurrentSection()
{
	return currentnode->getName();
}

Dictionary<XMLTree> *TTGXMLTree::getSubSections()
{
	Dictionary<XMLTree> *res = Dictionary<XMLTree>::create(this->getSubSectionCount());
	list<SectionNode *>::iterator it = currentnode->sectionnodes.begin();
	while (it != currentnode->sectionnodes.end())
	{
		res->add(new TTGXMLTree(access, *it, this->getExplorers()));
		it++;
	}
	return res;
}

bool TTGXMLTree::openNextSection()
{
	if (currentnode->sectionit != currentnode->sectionnodes.end())
	{
		currentnode = *(currentnode->sectionit++);
		return true;
	}
	return false;
}

//ro

bool TTGXMLTree::getNextAttribute(const char *&attr, const char *&val)
{
	if (currentnode->attrit != currentnode->attrnodes.end())
	{
		AttributeNode *res = *(currentnode->attrit++);
		attr = res->getName();
		val = res->getValue();
		return true;
	}
	return false;
}

bool TTGXMLTree::getStringAttribute(const char *attr, const char *&val)
{
	list <AttributeNode *>::iterator it = currentnode->attrnodes.begin();
	while (it != currentnode->attrnodes.end())
		if (!strcmp((*it)->getName(), attr))
		{
			val = (*it)->getValue();
			return true;
		}
		else
			it++;
	return false;
}

//wo

void TTGXMLTree::addSection(const char *section)
{
	if (access == XML_WO)
	{
		currentnode->sectionnodes.push_back(
			const_cast<SectionNode *const>(new SectionNode(section, currentnode)));
	}
	else
		throw Error(Error::LOCAL, "This tree is read only");
}

void TTGXMLTree::addSectionAndOpen(const char *section)
{
	if (access == XML_WO)
	{
		SectionNode *s = new SectionNode(section, currentnode);
		currentnode->sectionnodes.push_back(s);
		this->currentnode = s;
	}
	else
		throw Error(Error::LOCAL, "This tree is read only");
}

void TTGXMLTree::addStringAttribute(const char *attr, const char *val)
{
	if (access == XML_WO)
	{
		currentnode->attrnodes.push_back(
			const_cast<AttributeNode *const>(new AttributeNode(attr, val)));
	}
	else
		throw Error(Error::LOCAL, "This tree is read only");
}

TTGXMLTree::~TTGXMLTree()
{
	close();
}
